#pragma once
#include <QByteArray>
#include <QString>
// 帧格式常量定义
#define FRAME_HEADER1  0xA5       // 帧头第一个字节
#define FRAME_HEADER2  0x5A       // 帧头第二个字节
#define FRAME_RESERVED  0x00     // 保留字节
#define FRAME_TOTAL_LENGTH  12       // 帧总长度（Byte0-Byte11）
#define DOWNSTREAM_PARAMETERS_LENGTH  8          // 下行参数区域长度（Byte4-Byte11）
#define UPSTREAM_PARAMETERS_LENGTH  9          // 下行参数区域长度（Byte4-Byte11）

/**
 * @brief 下行指令命令码枚举
 * 根据设备通信协议定义的所有命令代码
 * 每个命令码对应一个特定的设备操作功能
 */
enum class FrameCommandCode : uint8_t
{
    // 下行指令（上位机发送给设备）
    FOCUS_MODE_SET = 0x01,      // 聚焦模式设置
    SCAN_MODE_SET = 0x02,       // 扫描模式设置
    MCP_GATING = 0x03,          // MCP门控设置
    CATHODE_GATING = 0x04,      // 阴极门控设置
    MCP_GAIN = 0x05,            // MCP增益设置
    GEAR_SET = 0x06,            // 档位设置
    TRIG_DELAY_ENABLE = 0x07,   // Trig是否经过延时设置（暂不使用）
    SHUTTER_CONTROL = 0x08,     // 快门开关控制
    TTL_STATUS_READ = 0x09,     // 20路TTL输出状态读回
    TRIGGER_SOURCE_SET = 0x0B,  // CCD&MCP触发源选择
    INTERNAL_TRIGGER_ONCE = 0x0C, // 内触发1次
    STPW_FAST_COMPONENT = 0x10, // STPW寄存器配置值，快组件
    STPW_MIDDLE_COMPONENT = 0x11, // STPW寄存器配置值，中组件
    STPW_SLOW_COMPONENT = 0x12, // STPW寄存器配置值，慢组件
    INTERNAL_TRIGGER_DELAY = 0x13, // 内触发模式下延时参数设置
    EXTERNAL_TRIGGER_ENABLE = 0x14, // 外触发信号使能设置
    SERIAL_DEVICE_QUERY = 0x50, // 串口设备地址查询命令
    MONITOR_SIGNAL_QUERY = 0x55, // 监控信号查询命令
    
    // 上行指令（设备发送给上位机）
    AD_VALUE_SEND = 0x34,       // 发送AD值
    GPIO_STATUS_SEND = 0x35,    // 发送GPIO状态
    TTL_OUTPUT_STATUS_SEND = 0x36, // 发送TTL输出状态
    COMMAND_PARSE_SUCCESS = 0x53 // 命令成功解析应答
};

/**
 * @brief 命令帧构建器类
 * 负责根据设备通信协议构建正确的下行指令帧
 * 提供通用构建方法和针对特定命令的便捷构建方法
 */
class CommandFrameBuilder
{

public:
    /**
     * @brief 构造函数
     * 初始化命令帧构建器
     */
    CommandFrameBuilder();
    
    /**
     * @brief 析构函数
     * 清理资源
     */
    ~CommandFrameBuilder();

    /**
     * @brief 获取帧总长
     * @return  帧总长
     */
    uint32_t getFrameTotalLength();

    /**
     * @brief 构建聚焦模式命令帧
     * 命令码：0x01
     * @return 聚焦模式命令帧
     */
    QByteArray buildFocusModeFrame();
    
    /**
     * @brief 构建扫描模式命令帧
     * 命令码：0x02
     * @param scanMode 扫描模式 (0:单次外触发, 1:单次内触发, 2:重频外触发, 3:重频内触发)
     * @return 扫描模式命令帧
     */
    QByteArray buildScanModeFrame(uint8_t scanMode);
    
    /**
     * @brief 构建MCP门控设置命令帧
     * 命令码：0x03
     * @param mode 门控模式（1:门控开+外触发, 2:门控开, 3:门控关）
     * @param delayNs 延时时间（纳秒，范围0-2ms）
     * @param pulseWidthNs 脉宽时间（纳秒，范围0-2ms）
     * @return MCP门控设置命令帧
     */
    QByteArray buildMCPGatingFrame(uint8_t mode, uint32_t delayNs, uint32_t pulseWidthNs);
    
    /**
     * @brief 构建阴极门控设置命令帧
     * 命令码：0x04
     * @param mode 门控模式（1:门控开+外触发, 2:门控开, 3:门控关）
     * @param delayNs 延时时间（纳秒，范围0-2ms）
     * @param pulseWidthNs 脉宽时间（纳秒，范围0-2ms）
     * @return 阴极门控设置命令帧
     */
    QByteArray buildCathodeGatingFrame(uint8_t mode, uint32_t delayNs, uint32_t pulseWidthNs);
    
    /**
     * @brief 构建MCP增益设置命令帧
     * 命令码：0x05
     * @param gain1 增益一的值（范围0-800，单位：V）
     * @param gain2 增益二的值（范围0-800，单位：V）
     * @return MCP增益设置命令帧
     */
    QByteArray buildMCPGainFrame(uint16_t gain1, uint16_t gain2);
    
    /**
     * @brief 构建档位设置命令帧
     * 命令码：0x06
     * @param gearPosition 档位位置值（bit7对应最高档）
     * @param componentSelection 组件选择（1:快组件, 2:中组件, 3:慢组件）
     * @return 档位设置命令帧
     */
    QByteArray buildGearSetFrame(uint8_t gearPosition, uint8_t componentSelection);
    
    /**
     * @brief 构建快门控制命令帧
     * 命令码：0x08
     * @param open true:打开快门, false:关闭快门
     * @return 快门控制命令帧
     */
    QByteArray buildShutterControlFrame(bool open);
    
    /**
     * @brief 构建触发源选择命令帧
     * 命令码：0x0B
     * @param source 触发源（0:由扫描触发线触发, 1:由门控触发接口触发）
     * @return 触发源选择命令帧
     */
    QByteArray buildTriggerSourceFrame(uint8_t source);
    
    /**
     * @brief 构建TTL状态读回命令帧
     * 命令码：0x09
     * @return TTL状态读回命令帧
     */
    QByteArray buildTTLStatusReadFrame();
    
    /**
     * @brief 构建内部触发一次命令帧
     * 命令码：0x0C
     * @return 内部触发一次命令帧
     */
    QByteArray buildInternalTriggerFrame();
    
    /**
     * @brief 构建STPW寄存器配置命令帧
     * @param componentType 组件类型（0:快组件, 1:中组件, 2:慢组件）
     * @param gearPositionValeu 当前设置的档位值
     * @return STPW寄存器配置命令帧
     */
    QByteArray buildSTPWFrame(uint8_t componentType, QVector<uint16_t> gearPositionValeu);
    
    /**
     * @brief 构建内部触发模式下延时参数设置命令帧
     * 命令码：0x13
     * @param delayNs 延时时间（纳秒，范围0-2ms）
     * @param pulseWidthNs 脉宽时间（纳秒，范围0-2ms）
     * @return 内部触发延时设置命令帧
     */
    QByteArray buildInternalTriggerDelayFrame(uint32_t delayNs, uint32_t pulseWidthNs);
    
    /**
     * @brief 构建外触发信号使能设置命令帧
     * 命令码：0x14
     * @param enabled 使能状态（true:使能外触发, false:切断外触发）
     * @return 外触发使能设置命令帧
     */
    QByteArray buildExternalTriggerEnableFrame(bool enabled);
    
    /**
     * @brief 构建串口设备地址查询命令帧
     * 命令码：0x50
     * @return 串口设备查询命令帧
     */
    QByteArray buildSerialDeviceQueryFrame();
    
    /**
     * @brief 构建监控信号查询命令帧
     * 命令码：0x55
     * @return 监控信号查询命令帧
     */
    QByteArray buildMonitorSignalQueryFrame();
    
    /**
     * @brief 解析上行指令帧
     * 验证帧格式并识别命令类型
     * @param frame 接收到的上行指令帧
     * @param commandCode 输出参数，解析出的命令码
     * @return 是否解析成功
     */
    bool parseUpstreamFrame(const QByteArray& frame, uint8_t& commandCode);
    
    /**
     * @brief 解析AD值数据帧
     * 命令码：0x34
     * @param frame 接收到的AD值帧
     * @param data 输出参数，解析出的AD值数据
     * @return 是否解析成功
     */
    bool parseADValueFrame(const QByteArray& frame, QVector<uint16_t>& adValues);
    
    /**
     * @brief 解析GPIO状态帧
     * 命令码：0x35
     * @param frame 接收到的GPIO状态帧
     * @param data 输出参数，解析出的GPIO状态数据
     * @return 是否解析成功
     */
    bool parseGPIOStatusFrame(const QByteArray& frame, QVector<bool>& gpioStatus);
    
    /**
     * @brief 解析TTL输出状态帧
     * 命令码：0x36
     * @param frame 接收到的TTL输出状态帧
     * @param data 输出参数，解析出的TTL状态数据
     * @return 是否解析成功
     */
    bool parseTTLStatusFrame(const QByteArray& frame, QVector<bool>& ttlStatus);
    
    /**
     * @brief 解析命令成功解析应答帧
     * 命令码：0x53
     * @param frame 接收到的应答帧
     * @return 是否解析成功
     */
    bool parseCommandParseSuccessFrame(const QByteArray& frame);
    
private:

    /**
     * @brief 构建通用命令帧
     * 构建包含指定命令码和参数的标准命令帧
     * @param commandCode 命令代码
     * @param parameters 参数数据（最多8字节）
     * @return 完整的12字节命令帧
     */
    QByteArray buildCommandFrame(uint8_t commandCode, const QByteArray& parameters = QByteArray());

    /**
     * @brief 辅助方法：将整数转换为字节数组（大端序）
     * @param value 整数值
     * @param byteCount 字节数
     * @return 字节数组（大端序）
     */
    QByteArray intToBigEndianBytes(uint32_t value, int byteCount);
    
    /**
     * @brief 辅助方法：将纳秒转换为正确的编码格式（用于延时和脉宽参数）
     * 按照协议规范将时间参数编码为3字节格式
     * @param timeNs 时间值（纳秒）
     * @return 编码后的3字节数组
     */
    QByteArray encodeTimeParameter(uint32_t timeNs);

    /**
     * @brief 获取命令描述
     * 根据命令码获取对应的中文描述
     * @param commandCode 命令代码
     * @return 命令描述字符串
     */
    QString getCommandDescription(uint8_t commandCode);
};
